#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QTimer>
#include <QFileInfo>
#include <QHeaderView>
#include <QDebug>
#include <QMenu>
#include <QCursor>
#include <QClipboard>
#include <QMessageBox>
#include <QDateTime>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    mUpdatedbThread(new UpdatedbThread(this)),
    mTrayIcon(new QSystemTrayIcon(this)),
    mProcess(new QProcess(this))
{
    ui->setupUi(this);

    initSystemTrayIcon();
    initWidgets();

    // init updatedb thread
    connect(mUpdatedbThread->worker(), SIGNAL(updating()),     this, SLOT(onUpdatedbStart()));
    connect(mUpdatedbThread->worker(), SIGNAL(finished()),     this, SLOT(onUpdatedbFinish()));
    connect(mUpdatedbThread->worker(), SIGNAL(error(QString)), this, SLOT(onUpdatedbError(QString)));

    mUpdatedbThread->start();

    // init mProcess
    connect(mProcess, SIGNAL(started()),     this, SLOT(onProcessStarted()));
    connect(mProcess, SIGNAL(finished(int)), this, SLOT(onProcessFinished(int)));
    connect(mProcess, SIGNAL(readyReadStandardOutput()),
            this, SLOT(onProcessReadyReadStandardOutput()));

    // init updatedb timer
    mUpdatedbTimer = new QTimer(this);
    mUpdatedbTimer->setInterval(10000);

    connect(mUpdatedbTimer, SIGNAL(timeout()),     this, SLOT(updatedb()));
    connect(ui->updatedb,   SIGNAL(clicked(bool)), this, SLOT(updatedb()));

    mUpdatedbTimer->start();
}

MainWindow::~MainWindow()
{
    mUpdatedbThread->quit();
    mUpdatedbThread->wait();

    delete ui;
}

void MainWindow::on_lineEdit_returnPressed()
{
    on_search_clicked();
}

void MainWindow::on_search_clicked()
{
    if (mIsUpdatingDb) {
        QMessageBox msgBox(this);
        msgBox.setWindowTitle("提示");
        msgBox.setText("正在执行updatedb，请稍后！");
        msgBox.exec();
        return;
    }

    mIsSearching = !mIsSearching;

    if (mIsSearching) {
        ui->search->setText("取消");

        ui->tableWidget->setRowCount(0);
        mProcessOutput.clear();

        QStringList cmd;
        cmd.append(ui->lineEdit->text());

        mProcess->start("locate", cmd);
    } else {
        ui->search->setText("搜索");
        mProcess->kill();
    }

}

void MainWindow::onUpdatedbStart()
{
    ui->statusBar->showMessage("updatedb...");
}

void MainWindow::onUpdatedbFinish()
{
    ui->statusBar->clearMessage();
    mIsUpdatingDb = false;
}

void MainWindow::onUpdatedbError(const QString &msg)
{
    QString text("updatedb error:\n  %1");
    text = text.arg(msg);

    mUpdatedbTimer->stop();

    QMessageBox msgBox(this);
    msgBox.setWindowTitle("提示");
    msgBox.setText(text);
    msgBox.exec();
}

void MainWindow::initWidgets()
{
    QStringList headerLabels = {"名称", "路径", "大小(Bytes)", "最后修改"};
    ui->tableWidget->setColumnCount(headerLabels.size());
    ui->tableWidget->setHorizontalHeaderLabels(headerLabels);

    QHeaderView* headerView = ui->tableWidget->horizontalHeader();
    headerView->resizeSection(0, 200);
    headerView->resizeSection(1, 400);

    ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);
}

void MainWindow::on_tableWidget_customContextMenuRequested(const QPoint & /*pos*/)
{
    if (ui->tableWidget->currentItem() == nullptr)
        return;

    int row = ui->tableWidget->currentRow();

    QMenu menu;
    QAction* copyFileName = menu.addAction("复制文件名");
    QAction* copyPath     = menu.addAction("复制所在路径");
    QAction* copyFullPath = menu.addAction("复制完整路径和文件名");

    QString text;

    QAction* action = menu.exec(QCursor::pos());
    if (action == copyFileName)
        text = ui->tableWidget->item(row, 0)->text();
    else if (action == copyPath)
        text = ui->tableWidget->item(row, 1)->text();
    else if (action == copyFullPath)
        text = ui->tableWidget->item(row, 0)->data(Qt::UserRole).toString();

    QApplication::clipboard()->setText(text);
}

void MainWindow::onProcessStarted()
{
    ui->statusBar->showMessage("searching...");
}

void MainWindow::onProcessFinished(int exitCode)
{
    Q_UNUSED(exitCode);

    ui->statusBar->clearMessage();

    mIsSearching = false;
    ui->search->setText("搜索");
}

void MainWindow::onProcessReadyReadStandardOutput()
{
    ui->tableWidget->setSortingEnabled(false);

    mProcess->setCurrentReadChannel(QProcess::StandardOutput);
    while (mProcess->canReadLine()) {
        QString line = mProcess->readLine().trimmed();

        QFileInfo fileInfo(line);
        if (!fileInfo.exists())
            continue;

        int row = ui->tableWidget->rowCount();
        ui->tableWidget->insertRow(row);
        ui->tableWidget->setItem(row, 0, new QTableWidgetItem(fileInfo.fileName()));
        ui->tableWidget->setItem(row, 1, new QTableWidgetItem(fileInfo.path()));

        QTableWidgetItem* sizeItem = new QTableWidgetItem(QString::number(fileInfo.size()));
        sizeItem->setTextAlignment(Qt::AlignVCenter | Qt::AlignRight);
        ui->tableWidget->setItem(row, 2, sizeItem);

        QDateTime dateTime = fileInfo.lastModified();

        QTableWidgetItem* lastModifiedItem =
                new QTableWidgetItem(dateTime.toString("yyyy-MM-dd hh:mm:ss"));
        lastModifiedItem->setTextAlignment(Qt::AlignCenter);
        ui->tableWidget->setItem(row, 3, lastModifiedItem);

        ui->tableWidget->item(row, 0)->setData(Qt::UserRole, fileInfo.filePath());
        ui->tableWidget->item(row, 0)->setIcon(mFileIconrovider.icon(fileInfo));
    }

    ui->tableWidget->setSortingEnabled(true);
}

void MainWindow::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason)
{
    if (reason == QSystemTrayIcon::DoubleClick)
        show();
}

void MainWindow::updatedb()
{
    if (mIsSearching || mIsUpdatingDb)
        return;

    mIsUpdatingDb = true;
    QMetaObject::invokeMethod(mUpdatedbThread->worker(), "updatedb");
}

void MainWindow::initSystemTrayIcon()
{
    QIcon icon(":/res/icon-search.png");
    QApplication::setWindowIcon(icon);

    mTrayIcon->setIcon(icon);

    QMenu* menu = new QMenu(this);
    menu->addAction("显示窗口", this, SLOT(show()));
    menu->addAction("退出程序", qApp, SLOT(quit()));
    mTrayIcon->setContextMenu(menu);

    connect(mTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this, SLOT(onTrayIconActivated(QSystemTrayIcon::ActivationReason)));

    mTrayIcon->show();
}
